Developing a Poker Game with Liberty Basic

© 2004, Gordon Rahman

author contact:

grahman@planet.nl

Home

Random Access Files

Liberty Simple Help2

Scrolling Background

Blood Presure Sim

Cellular Automata

Making Poker Game

Desktop Shortcuts2

Beginners Programming

Demos

Newsletter help

Index


Poker Game with Liberty Basic

[Editor: Please note - I have taken a little editorial liberty with Gordon's article. To be sure, it is an interesting premiss and worth study.]

If you haven't the slightest idea what to program with LB, maybe this is the push you were looking for. I'll try to get you interested in programming a draw poker game. You can download the full version, but it's better to read on.

I like to program games. Even though I don't play games that very often. Of course I don't mean those games where scores of people have to work at. There are many things to discover or learn while programming, that's what I like to talk about. So here is a tutorial about programming a game.

The last time I started with my tutorial I didn't finished either the game or the tutorial. The game was huge and so the tutorial became huge too. Here is a smaller game. This is more concept and less a finished game. What I plan to do is to create a poker hand of cards. That means I will display five cards. Then the program will evaluate the hand. The program will tell you what is significant in your hand. At last the program advices you which cards to keep.

Screen picture from full version game (when it is eventually done)

[Editor: Since the game does not play the other hand, or the betting and play component, maybe this will serve as Gordon's challenge for the reader. He has created a good platform to extend from.]

Let's play poker. Draw (or bluff) poker that is what I am talking about.

Getting Ready:

Get the QCARD32.DLL by Stephen Murphy from website:

http://www.telusplanet.net/public/stevem/

Study the card demo programs by Alyce (a former open source project) at: http://alycesrestaurant.com/

Here is the plan A:

I learned the rank order from the poker game at http://www.rahsoftwareuk.co.uk/

Setting up the Board


nomainwin
WindowWidth=DisplayWidth
WindowHeight=DisplayHeight
UpperLeftX =1 : UpperLeftY=1

    dim R(52),card(52),suit$(52),Gcard(52,2),suit(13),A(10)

    st$(1) = "clubs"   :st$(2) = "diamonds" : st$(3) = "hearts"  :st$(4) = "spades"

'-----------------------------------------------------------------------------------------------
'JPEG files are loaded with jpeg.dll (Alyce)
'So you need this DLL as well if you want to use the code below

    'Setup and load JPG files
     Open "jpeg.dll" for DLL as #j
     calldll #j, "LoadImageFile",_
     hWnd as ulong,_
     "pokb4.jpg" as ptr,_
      pokerbord as ulong
      Close #j

    loadbmp "pokerbord",pokerbord

'-------------------------------------------------------------------------------------------------

Above is the usual stuff for working with JPEG files. I use the JPEG.DLL from Alyce to load a JPEG picture as the background for the game. JPEG images are much smaller then Bitmap images. But if you want you may skip the code above and use the native LB drawing commands.

[Editor: This will load the basic game window shown below]

This is the graphic window we are going to use for displaying the cards. By using the WindowWidth and Height parameters we will create a full screen window.


    graphicbox #1.g, 0, 0, WindowWidth,WindowHeight 
  
  Open "Card Game" for window_nf as #1
    #1 "trapclose [quit]"

These four lines are an alternative if you don't use the pokb4.jpg picture.


'********************************
    #1.g "down; fill darkgreen" 	
    #1.g "getbmp pokerbord 0 0 1024 768"
    #1.g "drawbmp pokerbord 0 0 ;flush"
    #1.g "background pokerbord"
'********************************

These two lines are needed if you have loaded the pokerbord.


'-----------------------------------------------------------------------------------
    #1.g "down"                         		'pen down to draw background
    #1.g "drawbmp pokerbord 0 0 ;flush" 	'the background
'------------------------------------------------------------------------------------

    hBox=hwnd(#1.g)                     'get the window graphicbox handle to display the cards

This last line is needed if you use third party DLL's as we'll do with the QCARD dll. We will tell the dll to display in the graphicbox. So we need this window handle name.


    Open "qcard32.dll" for dll as #qc   'open the DLL
    Call InitializeDeck hBox            'initialize the deck.

The call to InitalixeDeck is, as the writer of the DLL told us, done first and only one time.


     playwave "shuffle.wav",sync     'intro a shuffle. This wave file comes together with
									'the QCARD32.DLL zip file.

This is how the cards in the deck are placed in QCARD32.DLL

Note that the first card of each suit is the Ace of that suit.

The sequential number of the cards is 1 to 52, so cards number 1, 14, 27 and 40 are aces

The problem with this order of cards is that the suit starts with the Ace. When we would want to sort the suit, the Ace will be the first (lowest rank) card. Maybe you could come up with a better idea. Suppose the deck had 53 cards.

Joker, 2,3,4,5,…K,A of clubs, 2,3,4,……K,A of spades.

That's where the modulus routines would be handy to have.

Someday I hope to ask Stephen Murphy to reconstruct another DLL with the poker order of cards. Or even better, maybe he can expand the existing QCARD32 DLL with an extra set of cards.

The main part of the tutorial continues here.


    Prompt "What is your name? ";yourName$

We will create an administrator mode to do some testing when that is needed.

If you answer the prompt with "admin" then you can select your hand by yourself.

Administrators can get a four of clubs by inserting 4c when asked for a card.

To receive a ten of hearts, the admin should insert 10h. Jack = 11 Queen = 12 and 13 = King.


'--------display five cards----------------------------

     for i = 1 to 5
[newCard] 
	 cnum = int(rnd(1)*52)+1	'card number cnum varies between 1 and 52

I wonder why Carl didn't just gave us some kind of RaND(52) function to seed a random number between 1 and 52. Are there volunteers to write that function?

[Editor: The reason that RND works the way it does is bacward support for QB, standard implementation across languages (many languages do it this way) and this is how Carl wanted to do it. The function mentioned would be easy to implement.]

Now here is where we deal with the administrator mode.


            if yourName$ ="admin" then
           		prompt "choose a card (number + [cdhs]) ";cnum$
                        if cnum$="quit" then [quit]
            	cardValue=Val(left$(cnum$,len(cnum$)-1))
            	cardSuit=instr("cdhs",right$(cnum$,1))
            	cnum = cardValue+(cardSuit-1)*13
            end if

Pretty neat, don't you think?

The variable cardValue Val(left$(cnum$,len(cnum$)-1)) will get the value of the first or first and second digit from the input (cnum$). While cardSuit instr("cdhs",right$(cnum$,1)) becomes 1 to 4 if the last character of the input matches on of the characters of the string "cdhs".

Cnum will now change through cnum = cardValue+(cardSuit-1)*13

If you don't want to be the admin, then you should enter a name (or just enter) to let the program deal 5 random cards of its own.

Now here is how we deal with the fact that the same card drawn from the deck can't be drawn again.


       if R(cnum) = -1 then
 goto [newCard]
	 else
        R(cnum)= -1 :card(i)=cnum
        End if

My way is not the formal way to program card drawing. Drawing cards from a deck goes like this. First you have to shuffle the deck.

1. Construct an array of 52 elements. Each element its sequential value


dim n(52)
for x=1 to 52
n(x)=x
next x

2. Now point to a spot in the array and swap that card with the last one in the array.

3. Shorten the array by one and repeat


for x=52 to 1 step -1
y=int(rnd(1)*x)+1
t=n(x)			'swap needs a temporary variable
n(x)=n(y)		'swap
n(y)=t			'swap current with last
next x

4. This is the result


for h = 1 to 52
print n(h);" ";
next h
end

The way I did means that I used two arrays to work with. I used an array for card picking and the second one to hold the administration. As I dimensioned the arrays, all their elements got zeroed. Now I pointed out to a spot in one array and look in the other array if I had pointed out to that spot before. Look how it goes.

1. The biggest disadvantage of my system is that the computer will have to do a lot of random tries to pick up the final cards.

2. This is no big disadvantage when we play a poker game with a maximum of only sixteen cards out of a 52 cards deck to pick. By the way you won't notice any time delay at the speed of your computer.


     dim n(52)
     dim a(52)
     for x = 1 to 52
[a]  y = int(rnd(0)*52)+1
     if a(y)=-1 then [a]
     n(x) = y :a(y) = -1		'mark the chosen spot in the reserve array
     next x

     for h = 1 to 52
     print n(h);" ";
     next h
     end

We don't have to use the next two variables in our program. The writer of the Qcard32.DLL provides these functions in his DLL:

'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 
GetCardColor(nCard)

GetCardSuit(nCard)

GetCardValue(nCard)

GetCardStatus(nCard) AND SetCardStatus(nCard, bStatus)
GetCardBlocked(nCard) AND AdjustCardBlocked(nCard, bValue)
IsCardDisabled(nCard), SetCardDisabled(nCard, bValue)
GetCardX(nCard), GetCardY(nCard)
SetCardX(nCard, nValue), SetCardY(nCard, nValue)
GetUsern(nCard) & SetUsern(nCard, nValue)

suit$(i) = st$(int((card(i)-.5)/13)+1)

Qcard(i) = card(i)-int((card(i)-.5)/13)*13

As a side step, here is a short listing just to do some testing:


s$(1)="clubs"
s$(2)="diamonds"
s$(3)="hearts"
s$(4)="spades"

    for t = 1 to 52
       s=int((t-.5)/13)+1
       v= t-s*13
       print "T ";t;" suit ";s$(s);" value ";v
    next t

Getting back to the game...


        Gcard(i,1) = int((card(i)-.5)/13)+1            		 'suit 1-4
        Gcard(i,2) = card(i)-int((card(i)-.5)/13)*13  	 'value 1-13

I programmed my own functions because I'll need to do some sorting. I need a double dimension array to be sorted Gcard(52,2). When you sort a two dimension array, both elements can be sorted, but even better the sorted elements keep their attributes. Please editors help me to explain this. It's like sorting records. The records will be sorted out while they keep their contents.

I didn't invent any of this. The method for finding the suit and value's of the cards, described above is called MODULUS.

From Alyce's Restaurant and Carl's function-library:

Modulus


function Modulus(number, divisor)
    Modulus=(number)-(int(number/divisor)*divisor)
    end function

The tutorial continues


     x=150+(i)*100 :y=50 :gosub [displCard]

     next i

'-------------------------------------------------------------------------------
   [startGame]

    '------ Flush test --------
        for N = 1 to 5
            for Z = 1 to 4
                if Gcard(N,1) = Z then A(Z)=A(Z)+1
            next Z
        next N
        for Z = 1 to 4
            if A(Z) = 5 then notice "flush ";st$(Z)
            if A(Z) = 4 then
                 notice "nearly flush in ";st$(Z)
                    for Z1 = 1 to 4
                        if A(Z1) = 1 then
                            dColour =Z1
                            for Z2 = 1 to 5
                                if Gcard(Z2,1) = dColour then dCard = Z2
                                'the colour and Gcard are now found
                            next Z2
                        end if
                    next Z1
                 notice "drop ";st$(Gcard(dColour,1));Gcard(dCard,2)
            end if
        next Z

The main action in this routine is if Gcard(N,1) = Z then A(Z)=A(Z)+1

The suit of every card is checked and placed in an array. Array A(1) contains the clubs while the spades are in A(4). So we can just compare the values of the elements of the array. This means if A(Z) = 5 then notice "flush ";st$(Z)

To evaluate the hand we can also look for the array elements with value 4. The chance to get the completing flush suit is (13-4) of the 42 left over cards. Maybe the other player also has a flush in this suit in his hand. That would drop the chances to get the flush to (13-9)/42.

The next step if the find the element that contains the breaking colour. The value of one other element must be 1 as there is an element with value 4.

------Test for straight------

This is how human look for straights.

Human are looking for the lowest card. Now when they have found this card they then search through their hand for the following card value. Doing this reveals if there is a straight in the hand.

Here is how you could find the lowest suit card easily.


    sort Gcard(), 1,5,2
    lowestValue = Gcard(1,2)
    highestValue= Gcard(5,2)

From the Liberty Help-file

Here is the syntax for the sort command:



    sort arrayName$(), i, j, [,n]

This sorts the array named arrayName$( starting with element i, and ending with element j. If it is a double dimensioned array then the column parameter tells which nth element to use as a sort key. Each WHOLE row moves with its corresponding key as it moves during the sort.

But things can easily be done too without sorting.

Take the first card and compare it with all the other cards in the hand.


    '----- lowest and highest suit card-----
        min = Gcard(1,2)
        max = Gcard(1,2)

        for Z = 2 to 5
            if Gcard(Z,2)< min then min = Gcard(Z,2)
            if Gcard(Z,2)> max then max = Gcard(Z,2)
        next Z
    '-----------------------------------------

So now take the min card and compare it with the four cards left. Look if there is a cards min+1 in the hand. If there is a min+1 then search the whole hand for a card with value min+2. Etc.


    for Z = 1 to 5
        if Gcard(Z,2) = min + 1 then
            for Z1 = 1 to 5
                if Gcard(Z1,2) = min + 2 then
                    for Z2 = 1 to 5
                        if Gcard(Z2,2) = min + 3 then
                            for Z3 = 1 to 5
                                if Gcard(Z3,2) = min + 4 then
                                    notice "straight highest card ";max
                                end if
                            next Z3
                        end if
                    next Z2
                end if
            next Z1
       end if
    next Z

    for Z = 1 to 5
        if Gcard(Z,2) = min + 1 then
            for Z1 = 1 to 5
                if Gcard(Z1,2) = min + 2 then
                    for Z2 = 1 to 5
                        if Gcard(Z2,2) = min + 3 then
                             notice "almost a straight drop ";max
                        end if
                    next Z2
                end if
            next Z1
       end if
    next Z


    for Z = 1 to 5
        if Gcard(Z,2) = max - 1 then
            for Z1 = 1 to 5
                if Gcard(Z1,2) = max - 2 then
                    for Z2 = 1 to 5
                        if Gcard(Z2,2) = max - 3 then
                                    notice "almost straight drop ";min
                        end if
                    next Z2
                end if
            next Z1
       end if
    next Z

-------------Test for the rest ------------------

There are several approaches towards this matter. I did it my way.

First I examined my hand to find how many aces, twos, threes, fours, fives, etc. it contains. Basically we did this method before while finding the suits.


   '----------- find all 13 ranks -----------
        for Z = 1 to 5
                rank(Gcard(Z,2)) = rank(Gcard(Z,2))+1	'as with suit(x)=suit(x)+1
        next Z

This is all there is to it. So if rank(6) = 2 then this means that there are two sixes in my hands.


    '----------- four of a kind----------
    for Z = 1 to 13
        if rank(Z) = 4 then
        notice "FOUR of a kind ";Z
            for Z1 = 1 to 13
            if rank(Z1) = 1 then
            notice "drop the";Z1
            end if
            next Z1
        end if
    next Z

    '----------- full house ------------
    for Z = 1 to 13
        if rank(Z) = 3 then
            for Z1 = 1 to 13
            if rank(Z1) = 2 then
            fullHouse = 1
            notice "FULL HOUSE ";Z
            end if
            next Z1
        end if
    next Z

    '------------ trio --------------
    for Z = 1 to 13
        if rank(Z) = 3 then
            for Z1 = 1 to 13
            if rank(Z1) = 1 then
            notice "Three of a kind ";Z :Z1=13
            end if
            next Z1
        end if
    next Z

    '------------ two pair-------------------
    TwoPair = 0
        for Z = 1 to 13
        if rank(Z) = 2 then
            for Z1 = Z+1 to 13
            if rank(Z1) = 2 then
            TwoPair = 1
            notice "Two pair ";Z;" and ";Z1
                for Z2 = 1 to 13
                if rank(Z2) = 1 then notice "drop ";Z2
                next Z2
            end if
            next Z1
        end if
    next Z


    '------------- one pair -----------------
    for Z = 1 to 13
        if rank(Z) = 2 and TwoPair=0 and fullHouse = 0 then
            for Z1 = Z+1 to 13
            if rank(Z1) >1 then
            Z1 = 13
            end if
            next Z1
        notice "One pair ";Z
        end if
    next Z

    '------------ high card -----------------
    'notice "Highest card ";Gcard(5,2);" ";st$(Gcard(5,1))
    notice "Highest card ";max


    redim R(52)
    redim card(52)
    redim suit$(52)
    redim Gcard(52,2)
    redim rank(13)
    redim A(10)

    goto [again]

wait

Okay smart guy. I never needed the sorting. I just wanted to explain MODULUS and show some use of that function. Programming the bluff poker game gets complicated with the cards arranged the way they are in the QCARD dll. So I can only use the DrawCard(hwnd, ncard, nx, ny) function that is provided with the dll. Nevertheless I enjoyed exploring it.

We will expand this program to a real poker game. The story continues.


[displCard]
        'window handle, card index number, x, y
        Call DealCard hBox,cnum,x,y
        playwave "card.wav",sync
        'pause 100 milliseconds between cards
        call Pause 100
        RETURN
wait

[quit] close #qc:close #1:end

There is no need to cut and paste this tutorial. I provided a good illustration of the snippets with a small demo. Please load the accompanying ZIP file [Editor: The zip file is included in the files archive which is part of the newsletter download - it is called NLPokerGame.zip] and have a taste of poker.

My next tutorial will cover the AI techniques needed to play bluff poker.